package com.wzdigit.wms.hm.service.hm.impl;
/*
 * @Author:yangwenbiao
 * @Date 2021/5/18 6:16 PM
 * @version 1.0
 */

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzdigit.framework.Shift;
import com.wzdigit.framework.exception.RestStatusException;
import com.wzdigit.mes.basic.api.BasicDataItemDetailApi;
import com.wzdigit.mes.basic.api.BasicParamApi;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.mes.basic.dto.DataItemDetailDTO;
import com.wzdigit.mes.basic.dto.ParamDetailDTO;
import com.wzdigit.wms.hm.client.req.CheckSNRequest;
import com.wzdigit.wms.hm.client.req.SnListRequest;
import com.wzdigit.wms.hm.client.resp.*;
import com.wzdigit.wms.hm.common.enums.*;
import com.wzdigit.wms.hm.domain.*;
import com.wzdigit.wms.hm.mapper.*;
import com.wzdigit.wms.hm.service.*;
import com.wzdigit.wms.hm.service.hm.HackingMachineService;
import com.wzdigit.wms.hm.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.BeanUtil;
import net.dreamlu.mica.core.utils.CollectionUtil;
import net.dreamlu.mica.core.utils.StringUtil;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.jws.WebService;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 改造LI HOUQI 的代码，直接搬过来，不做优化，也太难优化了
 */
@Component
@WebService(name = "HackingMachineService",
        targetNamespace = "http://impl.hm.service.hm.wms.wzdigit.com",
        endpointInterface = "com.wzdigit.wms.hm.service.hm.HackingMachineService")
@Slf4j
public class HackingMachineServiceImpl implements HackingMachineService {

    @Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;

    @Reference(version = "${dubbo.consumers.basic.data.item.detail.api:1.0.0}", check = false, timeout = 300000)
    BasicDataItemDetailApi basicDataItemDetailApi;

    @Autowired
    SkuMapper skuMapper;

    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    WarehouseMapper whsMapper;

    @Autowired
    GoodsManagerMapper goodsManagerMapper;

    @Autowired
    GoodsPkgMapper goodsPkgMapper;

//    @Autowired
//    ReceiveGoodsService service;

    @Autowired
    GoodsService goodsService;

    @Autowired
    QmsOqcManagerService qmsOqcManagerService;

    @Autowired
    AsnManagerService asnManagerService;

    @Autowired
    LotnoService lotnoService;

    @Autowired
    TrsnManagerService trsnManagerService;

    @Autowired
    InventoryService inventoryService;

    @Autowired
    AsnHeaderMapper asnHeaderMapper;

    @Autowired
    AsnDtlMapper asnDtlMapper;

    final String palletNoRuleCode = "virtualPalletCode";
    final String asnRuleCode = "ASN_R01";
    final String trsnRuleCode = "TRSN_ORDER";
    final String line2WhsDataItemCode = "LINE_TO_WHS";
    private static final String MDIC_HZ="MDIC_HZ";

    @Reference(version = "${dubbo.providers.basic.BasicParam.api:1.0.0}", check = false)
    BasicParamApi basicParamApi;


    /**
     * 看谁的代码我都觉得还有能看的，妈的，这个代码太恶心了，还要我搬过来，艹。怎么改造？直接搬过来算了
     *
     * @param input
     * @return
     */
//    @Override
//    public Result<Integer> palletizerSnReceive(SnListRequest input) {
    public StackingResult palletizerSnReceive(SnListRequest input) {

        if (input == null) {
            log.warn("入参为NULL");
        }

        log.info("入参：{}",input.toString());
        if (input.getID() ==null) {
            input.setID(0);
        }
        StackingResult stackingResult = new StackingResult();

        Result<Integer> resultReturn = new Result<>();

        PalletizerResultDto dto = new PalletizerResultDto();

        try {
//            if (input.getPRODUCT_SN().isEmpty() || input.getPRODUCT_SN().size() == 0) {
            if (input.getSNList().getString().isEmpty() || input.getSNList().getString().size() == 0) {
                resultReturn.setMessage("sn信息不能为空");
                resultReturn.setFlag(false);

                stackingResult.setId(input.getID().toString());
                stackingResult.setMsg("sn信息不能为空");
                stackingResult.setStatus("F");

                log.info("出参：{}",stackingResult);
                return stackingResult;
//                return resultReturn;
            }

            String userName = String.valueOf(input.getID());
//            Result result = this.receive(input.getPRODUCT_SN(), userName, "码垛机接收");
            Result result = this.receive(input.getSNList().getString(), userName, "码垛机接收");

//            dto.setID(input.getID());
//            dto.setSTATUS(result.isFlag() ? "T" : "F");
//            dto.setMSG(result.getMessage());

            resultReturn.setFlag(result.isFlag());
            resultReturn.setMessage(result.getMessage());
            result.setData(input.getID());


            stackingResult.setId(input.getID().toString());
            stackingResult.setMsg(result.getMessage());
            stackingResult.setStatus("S");

        } catch (RestStatusException ex) {

//            dto.setID(input.getID());
//            dto.setSTATUS("F");
//            dto.setMSG(ex.getContent());
            ex.printStackTrace();
            resultReturn.setFlag(false);
            resultReturn.setMessage(ex.getContent());


            stackingResult.setId(input.getID().toString());
            stackingResult.setMsg(ex.getContent());
            stackingResult.setStatus("F");

        } catch (Exception e) {
            e.printStackTrace();
            resultReturn.setFlag(false);
            resultReturn.setMessage(e.getMessage());

//            if (input.getID()==null) {
//                stackingResult.setId("");
//            }

            stackingResult.setId(input.getID().toString());
            stackingResult.setMsg(e.getMessage());
            stackingResult.setStatus("F");
        }
//        return resultReturn;


        log.info("出参：{}",stackingResult);
        return stackingResult;
    }

    /**
     * 码垛机扫描sn
     *
     * @param
     * @return
     */
    @Override
//    public Result<List<SnInforDto>> CheckSN(String sn) {
//    @XmlElementDecl(namespace = "http://pal.service.hm.wms.wzdigit.com" ,name ="CheckSNRequest")
//    public Result<List<SnInforDto>> CheckSN(CheckSNRequest checkSNRequest) {
    public CheckSnResult CheckSN(CheckSNRequest checkSNRequest) {
        long startTime = new Date().getTime();
        log.info("进入码垛机检查SN接口,开始毫秒数："+startTime);
        if (checkSNRequest == null) {
            log.warn("入参为NULL");
        }

        log.info("入参:{}", checkSNRequest.toString());

        Result<List<SnInforDto>> result = new Result<>();
        String sn =checkSNRequest.getPRODUCT_SN();

        CheckSnResult checkSnResult = new CheckSnResult();

        List<SnInforDto> snInforDtos = new ArrayList<>();
        try {
            snInforDtos = selectSnInfosBySn(sn, SnScanTypeEnum.SELECT_SN);
        } catch (RestStatusException e) {
            e.printStackTrace();
            result.setMessage(e.getContent());
            result.setFlag(false);

            checkSnResult.setStatus("F");
            checkSnResult.setMsg(e.getContent());
            long endTime = new Date().getTime();
            log.info("码垛机检查SN接口异常,结束毫秒数："+endTime);
            log.info("码垛机检查SN接口异常总耗时(毫秒)："+(endTime-startTime));
            log.info("出参：{}",checkSnResult);
            return checkSnResult;
//            return result;
        } catch (Exception e) {
            e.printStackTrace();

            result.setMessage(e.getMessage());
            result.setFlag(false);

            checkSnResult.setStatus("F");
            checkSnResult.setMsg(e.getMessage());
            log.info("出参：{}",checkSnResult);
            return checkSnResult;
//            return result;
        }

        if (snInforDtos.size() == 0) {
            String msg = String.format("没有找到sn[%s]的信息!", sn);
            result.setMessage(msg);
            result.setFlag(false);

            checkSnResult.setStatus("F");
            checkSnResult.setMsg(msg);
            log.info("出参：{}",checkSnResult);
            return checkSnResult;
//            return result;
        }

        for (SnInforDto item : snInforDtos) {
            if (item.getWhsId() != null) {
                String msg = String.format("当前SN[%s]已经交收!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;
//                return result;
            }

            if (item.getOwner() == null || "".equals(item.getOwner())) {
                String msg = String.format("当前SN[%s]货主为空!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;

//                return result;
            }

          /*  if (item.getInspNo() == null || "".equals(item.getInspNo())) {
                String msg = String.format("当前SN[%s]送检单为空!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;

//                return result;
            }*/

            if (item.getFactory() == null || "".equals(item.getFactory())) {
                String msg = String.format("当前SN[%s]组织为空!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;
//                return result;
            }

            if (item.getPoNo() == null || "".equals(item.getPoNo())) {
                String msg = String.format("当前SN[%s]PO为空!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;

//                return result;
            }

            if (item.getSoNo() == null || "".equals(item.getSoNo())) {
                String msg = String.format("当前SN[%s]销售订单为空!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;
//                return result;
            }

            if (item.getSoItem() == null || "".equals(item.getSoItem())) {
                String msg = String.format("当前SN[%s]销售订单行号为空!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;

//                return result;
            }

            if (!item.getStatus().equals(GoodsStatusEnum.CREATE.getCode())) {
                String msg = String.format("当前SN[%s]不为建档状态!", sn);
                result.setMessage(msg);
                result.setFlag(false);

                checkSnResult.setStatus("F");
                checkSnResult.setMsg(msg);
                log.info("出参：{}",checkSnResult);
                return checkSnResult;
//                return result;
            }
        }
        result.setData(snInforDtos);

        checkSnResult.setStatus("S");
        checkSnResult.setMsg(result.toString());
        long endTime = new Date().getTime();
        log.info("结束码垛机检查SN接口,结束毫秒数："+endTime);
        log.info("结束码垛机检查SN接口总耗时(毫秒)："+(endTime-startTime));
        log.info("出参：{}",checkSnResult);
        return checkSnResult;
    }

    //下面具体方法

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result receive(List<String> snList, String userName, String type) {
        //1.生成虚拟卡板号
        String pkgCode = this.basicSimpleCodeRuleApi.GenerateCode(this.palletNoRuleCode);
        return this.receiveNew(snList, pkgCode, userName, type,AsnTypeEnum.PRD_RECEIVE.code);
    }


    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result receiveNew(List<String> snList, String pkgCode, String userName, String dataSource,String asnType)  {
        if (snList.size() != snList.stream().distinct().count()) {
            Shift.fatal("传入重复数据!");
        }
        //获取goods信息
        List<Goods> goodsList = this.goodsService.selectListByListSn(snList);
        if (goodsList.size() != snList.size()) {
            List<String> existSn = goodsList.stream().map(Goods::getGoodsSn).distinct().collect(Collectors.toList());
            List<String> notExistSn = snList.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
            Shift.fatal("以下sn未同步:[" + String.join(",", notExistSn) + "]");
        }
        if (goodsList.stream().filter(t -> t.getStatus() == GoodsStatusEnum.CREATE.getCode()).count() < goodsList.size()) {
            List<String> existSn = goodsList.stream().filter(t -> t.getStatus() != GoodsStatusEnum.CREATE.getCode()).map(Goods::getGoodsSn).collect(Collectors.toList());
            Shift.fatal("以下sn状态不在建档状态:[" + String.join(",", existSn) + "]");
        }
        if (goodsList.stream().map(Goods::getPrdWo).distinct().count() > 1) {
            Shift.fatal("不同工单不允许打包在一个包装内!");
        }
        if (goodsList.stream().anyMatch(t -> "".equals(t.getLotno())||t.getLotno()==null)) {
            Shift.fatal("含未生成批次号的SN记录!");
        }
        if (goodsList.stream().anyMatch(t -> "".equals(t.getMfgLine())||t.getMfgLine()==null)) {
            Shift.fatal("含未生成制造工厂的SN记录!");
        }

        //获取码垛下线频率
        ParamDetailDTO paramDetailDTO = basicParamApi.getByCode(MDIC_HZ);
        String rateStr=paramDetailDTO.getSystemParamValue();
        Integer rate =- Integer.valueOf(rateStr);
        //截止时间：当前时间前推rateStr分钟
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE,rate);
        Date closeTime = calendar.getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        log.info("截止时间>>>>>>>>>"+sdf.format(closeTime));

        //生成栈板信息
        GoodsPkg newPkg = this.setGoodsPkg(pkgCode, userName);
        this.goodsService.getGoodsPkgMapper().insert(newPkg);
        newPkg.setUrl(String.format("%s_0", newPkg.getGoodsPkgId()));
        this.goodsService.getGoodsPkgMapper().updateUrlByGoodsPkgId(newPkg.getGoodsPkgId(), newPkg.getUrl());
        //根据产品、线体分组
        Map<String, List<Goods>> goodsMap = goodsList.stream().collect(
                Collectors.groupingBy(t -> t.getMfgLine() + "#" +
                        t.getSkuId(), Collectors.toList()));
        for (List<Goods> mapGoodsList : goodsMap.values()) {
            List<String> mapSnList = mapGoodsList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
            Goods mapGoods = mapGoodsList.get(0);
            //校验sn上是否收货
            List<String> receiveSnList = asnManagerService.searchIsReceive(mapGoods.getMfgLine(),
                    mapGoods.getSkuId(), mapGoods.getPrdWo(), mapSnList);
            if (CollectionUtil.isNotEmpty(receiveSnList)){
                Shift.fatal("以下条码已经收过货了:[" + StringUtil.join(receiveSnList,",") + "]");
            }
            AsnDtl asnDtl=new AsnDtl();
            //查询是否有截止时间往后的符合条件的收货单
            AsnHeader asnHeader=asnHeaderMapper.searchRecieveHeader(mapGoods.getMfgLine(),
                    mapGoods.getSkuId(), mapGoods.getPrdWo(),closeTime,AsnHeaderStatusEnum.PARTRECEIVE.code,AsnTypeEnum.PRD_RECEIVE.code);
            if (asnHeader==null){
                Sku sku = this.skuMapper.selectById(mapGoods.getSkuId());
                //生成新的收货单
                DataItemDetailDTO line2WhsItem = this.basicDataItemDetailApi.getDataItemDetailByPCodeAndName(this.line2WhsDataItemCode, mapGoods.getMfgLine());
                if (line2WhsItem == null) {
                    Shift.fatal("数据字典没有配置线体[" + mapGoods.getMfgLine() + "]对应的中转仓!");
                }
                Warehouse warehouse = this.whsMapper.selectOneByWhsCode(line2WhsItem.getRemark());
                if (warehouse == null) {
                    Shift.fatal("没有找到中转仓[" + line2WhsItem.getRemark() + "]信息!");
                }
                Integer toWhsId = warehouse.getWhsId();


                asnHeader = setAsnHeader(mapGoods, userName, toWhsId);
                asnHeader.setDataSource(dataSource);
                asnHeader.setAsnType(asnType);
                asnHeader.setUdf1(mapGoods.getPrdWo());
                asnHeader.setUdf2(mapGoods.getMfgLine());
                asnDtl = setAsnDetail(asnHeader, mapGoodsList.get(0), sku, userName);
                this.asnManagerService.addAsn(asnHeader, asnDtl);
            }else {
                //向符合的收货单添加sn
                asnDtl= asnDtlMapper.selectList(new QueryWrapper<AsnDtl>()
                        .eq("ASN_HEADER_ID", asnHeader.getAsnHeaderId())).get(0);
            }
            AsnDtlStatusEnum asnDtlStatus = AsnDtlStatusEnum.PARTRECEIVE;
            AsnHeaderStatusEnum asnHeaderStatus = AsnHeaderStatusEnum.PARTRECEIVE;
            BigDecimal nowQty = mapGoodsList.stream().map(Goods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            asnHeader.setStatus(asnHeaderStatus.getCode());
            asnDtl.setStatus(asnDtlStatus.getCode());
            //修改送货单明细的送货数量 & 状态
            this.asnManagerService.getAsnDtlService().getMapper().plusRecQtyAndOrderQtyById(
                    asnDtl.getAsnDtlId(),
                    nowQty,
                    asnDtlStatus.getCode(),//状态
                    userName
            );
            //添加送货单的货品信息
            List<AsnDtlGoods> asnDtlGoodsList = this.setAsnDtlGoodsList(mapGoodsList, userName, asnDtl);
            for (AsnDtlGoods item : asnDtlGoodsList) {
                this.asnManagerService.getAsnDtlGoodsService().getMapper().insert(item);
            }
            //记录入库凭证
            TrsnHeader trsnHeader=null;
            trsnHeader = this.handleTrsn(asnHeader, asnDtl, asnDtlGoodsList, trsnHeader, 0);
            //修改sn
            for (Goods item : mapGoodsList) {
                item.setPkgId(newPkg.getGoodsPkgId());
                item.setWhsId(asnHeader.getToWhs());
                item.setStatus(GoodsStatusEnum.WAIT_UP.getCode());
                item.setModifyUser(userName);
                item.setStockInDate(new Date());
                item.setModifyTime(new Date());
            }
            this.goodsService.getGoodsMapper().updatePkgIdAndStatusAndWhsIdBySnList(mapSnList, newPkg.getGoodsPkgId(), GoodsStatusEnum.WAIT_UP.getCode(), trsnHeader.getWhsId(), userName);

            //增加库存
            this.handleInventory(asnHeader, asnDtl, mapGoodsList, trsnHeader.getNoteNo(), 0, userName);
//            Shift.fatal("/////////////////");
        }

        return new Result(true, "操作成功!");
    }

    /**
     * 收货
     *
     * @param snList   sn列表
     * @param pkgCode  包装编码
     * @param userName 操作人
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result receiveOld(List<String> snList, String pkgCode, String userName, String type) {

        if (snList.size() != snList.stream().distinct().count()) {
            Shift.fatal("传入重复数据!");
        }

        //1. 获取sn信息
        List<Goods> goodsList = this.goodsService.selectListByListSn(snList);
        if (goodsList.size() != snList.size()) {
            List<String> existSn = goodsList.stream().map(Goods::getGoodsSn).distinct().collect(Collectors.toList());
            List<String> notExistSn = snList.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
            Shift.fatal("以下sn未同步:[" + String.join(",", notExistSn) + "]");
        }
        if (goodsList.stream().filter(t -> t.getStatus() == GoodsStatusEnum.CREATE.getCode()).count() < goodsList.size()) {
            List<String> existSn = goodsList.stream().filter(t -> t.getStatus() != GoodsStatusEnum.CREATE.getCode()).map(Goods::getGoodsSn).collect(Collectors.toList());
            Shift.fatal("以下sn状态不为新建状态:[" + String.join(",", existSn) + "]");
        }
        if (goodsList.stream().map(Goods::getPrdWo).distinct().count() > 1) {
            Shift.fatal("不同工单不允许打包在一个包装内!");
        }
        if (goodsList.stream().anyMatch(t -> "".equals(t.getLotno()))) {
            Shift.fatal("含未生成批次号的SN记录!");
        }
        for (Goods goods : goodsList) {
            if ("".equals(goods.getInspNo())) {
                Shift.fatal(String.format("sn[%s]没有找到送检单!", goods.getGoodsSn()));
            }
        }
        //2. 获取 送检单信息
        List<String> oqcBills = goodsList.stream().map(Goods::getInspNo).distinct().collect(Collectors.toList());
        List<QmsOqc> qmsOqcs = this.qmsOqcManagerService.selectListByOqcs(oqcBills);
        if (qmsOqcs.size() == 0) {
            Shift.fatal("找不到送检单信息:[" + String.join(",", oqcBills) + "]");
        }
        if (qmsOqcs.size() < oqcBills.size()) {
            List<String> existSn = qmsOqcs.stream().map(QmsOqc::getOqc).distinct().collect(Collectors.toList());
            List<String> notExistSn = oqcBills.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
            Shift.fatal("找不到送检单信息:[" + String.join(",", notExistSn) + "]");
        }
        Result result = this.asnManagerService.existReceiveGoods(oqcBills, snList);
        if (!result.isFlag()) {
            Shift.fatal("以下条码已经收过货了:[" + result.getMessage() + "]");
        }
        TrsnHeader trsnHeader = null;
        int rowIndex = 0;
        // 添加栈板信息
        GoodsPkg newPkg = this.setGoodsPkg(pkgCode, userName);
        this.goodsService.getGoodsPkgMapper().insert(newPkg);
        newPkg.setUrl(String.format("%s_0", newPkg.getGoodsPkgId()));
        this.goodsService.getGoodsPkgMapper().updateUrlByGoodsPkgId(newPkg.getGoodsPkgId(), newPkg.getUrl());
        // 按送检单创建/修改送货单 , 交易单 , 库存处理
        for (QmsOqc qmsOqc : qmsOqcs) {
            // 获取 goods 详细信息
            List<Goods> nowGoodsList = goodsList.stream().filter(t -> t.getInspNo().equals(qmsOqc.getOqc())).collect(Collectors.toList());
            //定义 ASN 单信息
            AsnHeader asnHeader = new AsnHeader();
            AsnDtl asnDtl = new AsnDtl();
            List<AsnDtlGoods> asnDtlGoodsList = new ArrayList<>();
            //调用asn单据处理
            this.handleAsn(qmsOqc, nowGoodsList, userName, asnHeader, asnDtl, asnDtlGoodsList, type);
            //定义 TRSN 单信息
            rowIndex++;
            //调用Trsn单据处理
            trsnHeader = this.handleTrsn(asnHeader, asnDtl, asnDtlGoodsList, trsnHeader, rowIndex);
            // 修改sn的父节点信息
            List<String> nowSnList = nowGoodsList.stream().map(Goods::getGoodsSn).collect(Collectors.toList());
            this.goodsService.getGoodsMapper().updatePkgIdAndStatusAndWhsIdBySnList(nowSnList, newPkg.getGoodsPkgId(), GoodsStatusEnum.WAIT_UP.getCode(), trsnHeader.getWhsId(), userName);
            for (Goods item : nowGoodsList) {
                item.setPkgId(newPkg.getGoodsPkgId());
                item.setWhsId(asnHeader.getToWhs());
                item.setStatus(GoodsStatusEnum.WAIT_UP.getCode());
                item.setModifyUser(userName);
                item.setStockInDate(new Date());
                item.setModifyTime(new Date());
            }
            //库存处理
            this.handleInventory(asnHeader, asnDtl, nowGoodsList, trsnHeader.getNoteNo(), rowIndex, userName);
        }
        return new Result(true, "操作成功!");
    }

    private GoodsPkg setGoodsPkg(String pkgCode, String userName) {
        GoodsPkg goodsPkg = new GoodsPkg();
        goodsPkg.setPkgSn(pkgCode);
        goodsPkg.setPkgLevel(1);
        goodsPkg.setPkgCategory("PALLET");
        goodsPkg.setPkgType(10);
        goodsPkg.setFatherPkgId(0);
        goodsPkg.setIsLeaf(BooleanEnum.TRUE.getCode());
        goodsPkg.setUrl(String.format("%s_0", goodsPkg.getGoodsPkgId()));
        goodsPkg.setCreateTime(new Date());
        goodsPkg.setModifyTime(new Date());
        goodsPkg.setCreateUser(userName);
        goodsPkg.setModifyUser(userName);
        return goodsPkg;
    }


    /**
     * 处理送货单信息
     *
     * @param qmsOqc            oqc单据信息
     * @param goodsList         sn清单信息
     * @param userName          操作人
     * @param r_asnHeader       收货单头
     * @param r_asnDtl          收货单明细
     * @param r_asnDtlGoodsList 收货sn信息
     */
    private void handleAsn(QmsOqc qmsOqc, List<Goods> goodsList, String userName, AsnHeader r_asnHeader, AsnDtl r_asnDtl, List<AsnDtlGoods> r_asnDtlGoodsList, String type) {
        //todo 先注释看看
        //1. 获取 货品信息
        Sku sku = this.skuMapper.selectById(goodsList.get(0).getSkuId());
//        Sku sku = new Sku();
        //2. 根据送检单获取送货单
        AsnHeader asnHeader;
        AsnDtl asnDtl = this.asnManagerService.getAsnDtlService().selectOneByInspNo(qmsOqc.getOqc());
        if (asnDtl == null) {
            //1. 获取 中转仓
            DataItemDetailDTO line2WhsItem = this.basicDataItemDetailApi.getDataItemDetailByPCodeAndName(this.line2WhsDataItemCode, goodsList.get(0).getMfgLine());
            if (line2WhsItem == null) {
                Shift.fatal("数据字典没有配置线体[" + goodsList.get(0).getMfgLine() + "]对应的中转仓!");
            }
            Warehouse warehouse = this.whsMapper.selectOneByWhsCode(line2WhsItem.getRemark());
            if (warehouse == null) {
                Shift.fatal("没有找到中转仓[" + line2WhsItem.getRemark() + "]信息!");
            }
            Integer toWhsId = warehouse.getWhsId();
            //创建信息
            asnHeader = this.setAsnHeader(goodsList.get(0), userName, toWhsId);
            asnHeader.setDataSource(type);

            asnDtl = this.setAsnDetail(asnHeader, goodsList.get(0), sku, userName);
            this.asnManagerService.addAsn(asnHeader, asnDtl);
        } else {
            asnHeader = this.asnManagerService.getAsnHeaderService().getMapper().selectById(asnDtl.getAsnHeaderId());
        }
        //判断质检状态
        AsnDtlStatusEnum asnDtlStatus = AsnDtlStatusEnum.PARTRECEIVE;
        AsnHeaderStatusEnum asnHeaderStatus = AsnHeaderStatusEnum.PARTRECEIVE;
        BigDecimal nowQty = goodsList.stream().map(Goods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (qmsOqc.getStatus() == QmsOqcStatusEnum.CHECK_ACCESS.getCode()
                || qmsOqc.getStatus() == QmsOqcStatusEnum.CHECK_CONVICTED_BACK.getCode()
        ) {
            //已处理
            BigDecimal allQty = asnDtl.getRcvQty().add(nowQty);
            if (allQty.compareTo(qmsOqc.getSubmitInspQty()) == 0) {
                asnDtlStatus = AsnDtlStatusEnum.WHOLERECEIVE;
                asnHeaderStatus = AsnHeaderStatusEnum.FINISH;
            }
        }
        asnHeader.setStatus(asnHeaderStatus.getCode());
        asnDtl.setStatus(asnDtlStatus.getCode());
        //4. 修改送货单送货数量 / 状态
        this.asnManagerService.getAsnDtlService().getMapper().plusRecQtyAndOrderQtyById(
                asnDtl.getAsnDtlId(),
                nowQty,
                asnDtlStatus.getCode(),//状态
                userName
        );
        //5. 修改送货单状态
        this.asnManagerService.getAsnHeaderService().getMapper().updateStatusById(asnHeader.getAsnHeaderId(),
                asnHeaderStatus.getCode(),
                userName);
        //6. 添加送货单  货品清单
        List<AsnDtlGoods> asnDtlGoodsList = this.setAsnDtlGoodsList(goodsList, userName, asnDtl);
        for (AsnDtlGoods item : asnDtlGoodsList) {
            this.asnManagerService.getAsnDtlGoodsService().getMapper().insert(item);
        }
        BeanUtil.copy(asnHeader, r_asnHeader);
        BeanUtil.copy(asnDtl, r_asnDtl);
        r_asnDtlGoodsList.addAll(asnDtlGoodsList);
    }

    private TrsnHeader handleTrsn(AsnHeader asnHeader, AsnDtl asnDtl, List<AsnDtlGoods> asnDtlGoodsList, TrsnHeader trsnHeader, int rowIndex) {
        if (trsnHeader == null)
            trsnHeader = this.setTrsnHeader(asnHeader);
        TrsnDtl trsnDtl = this.setTrsnDtl(asnHeader, asnDtl, asnDtlGoodsList, rowIndex);
        List<TrsnDtlGoods> trsnDtlGoodsList = this.setTrsnDtlGoods(trsnDtl, asnDtlGoodsList);
        this.trsnManagerService.insertTrsnInfo(trsnHeader, trsnDtl, trsnDtlGoodsList);
        return trsnHeader;
    }

    private void handleInventory(AsnHeader asnHeader, AsnDtl asnDtl, List<Goods> goodsList, String noteNo, int rowIndex, String userName) {
        List<UpdateLocInventoryInputDto> list = new ArrayList<>();

        Map<String, List<Goods>> collect = goodsList.stream()
                .collect(Collectors.groupingBy(t ->
                                t.getWhsId() + "#" + t.getLocId() + "#" + t.getOwner() + "#" + t.getSkuId() + "#" + t.getFactory() + "#" + t.getVendorId() + "#" + t.getLotno() + "#" + t.getInvAttr() + "#" + t.getQaStatus() + "#",
                        Collectors.toList()));

        for (String key : collect.keySet()) {
            List<Goods> goodsCollect = collect.get(key);
            UpdateLocInventoryInputDto input = new UpdateLocInventoryInputDto();
            input.setWhsId(asnDtl.getWhsId());
            input.setOwner(asnHeader.getOwner());
            input.setSkuId(goodsCollect.get(0).getSkuId());
            input.setFactory(asnHeader.getFactory());
            input.setVendorId(asnHeader.getVendorId());
            input.setLotNo(goodsCollect.get(0).getLotno());
            input.setInvAttr(goodsCollect.get(0).getInvAttr());
            input.setQaStatus(goodsCollect.get(0).getQaStatus());
            input.setQty(goodsCollect.stream().map(Goods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add));
            input.setUnit(goodsCollect.get(0).getUnit());
            input.setOperator(userName);
            list.add(input);
        }
        for (UpdateLocInventoryInputDto input : list) {
            InvTrans log = new InvTrans();
            log.setOpCode(OpCodeEnum.RECEIVE.getCode());
            log.setDocType(asnHeader.getAsnType());
            log.setDocNo(asnDtl.getAsnNo());
            log.setDocLineNo(asnDtl.getAsnLineNo());
            log.setTrsnNo(noteNo);
            log.setTrsnLineNo(String.valueOf(rowIndex));
            log.setStatus(InvTransStatusEnum.FINISHED.getCode());
            log.setTransTime(new Date());
            log.setOperator(input.getOperator());
            log.setTransQty(input.getQty());
            log.setCreateTime(new Date());
            log.setModifyTime(new Date());
            log.setCreateUser(input.getOperator());
            log.setModifyUser(input.getOperator());

            this.inventoryService.inventoryIn(input, log);
        }
    }

    /**
     * 赋值 asnHeader
     *
     * @param goodsItem
     * @param userName
     * @param toWhsId
     * @return
     */
    private AsnHeader setAsnHeader(Goods goodsItem, String userName, Integer toWhsId) {
        AsnHeader asnHeader = new AsnHeader();
        asnHeader.setAsnNo(this.basicSimpleCodeRuleApi.GenerateCode(this.asnRuleCode));  //单号
        asnHeader.setAsnType(AsnTypeEnum.PRD_RECEIVE.getCode());
        asnHeader.setPriority(0);
        asnHeader.setOwner(goodsItem.getOwner());
        asnHeader.setAsnCreateTime(new Date());
        asnHeader.setExpectArriveTime1(new Date());
        asnHeader.setFactory(goodsItem.getFactory());
        asnHeader.setToWhs(toWhsId); //中转仓
        asnHeader.setVendorId(goodsItem.getVendorId());
        asnHeader.setPoNo(goodsItem.getPoNo());
        asnHeader.setDataSource("ERP");
        asnHeader.setReleaseStatus(BooleanEnum.FALSE.getCode());
        asnHeader.setAsnPrintFlag(BooleanEnum.FALSE.getCode());
        asnHeader.setQcStatus(QcStatusEnum.已创建质检单.getCode());  //判定结果
        asnHeader.setSnScan(BooleanEnum.FALSE.getCode());
        asnHeader.setRcvOverFlag(BooleanEnum.FALSE.getCode());
        asnHeader.setStatus(AsnHeaderStatusEnum.PARTRECEIVE.getCode());
        asnHeader.setCreateUser(userName);
        asnHeader.setModifyUser(userName);
        asnHeader.setCreateTime(new Date());
        asnHeader.setModifyTime(new Date());
        return asnHeader;
    }

    /**
     * 赋值 asnDetail
     *
     * @param asnHeader
     * @param goodsItem
     * @param sku
     * @param userName
     * @return
     */
    private AsnDtl setAsnDetail(AsnHeader asnHeader,
                                Goods goodsItem,
                                Sku sku,
                                String userName) {
        //1. 获取 goods 的批次属性值
        Lotno lotInfo = this.lotnoService.selectByCode(goodsItem.getLotno());
        if (lotInfo == null) {
            Shift.fatal("没有找到批次属性信息!");
        }
        AsnDtl asnItem = new AsnDtl();
        asnItem.setAsnNo(asnHeader.getAsnNo());
        asnItem.setAsnLineNo("1");

        asnItem.setPoNo(goodsItem.getPoNo());

        asnItem.setSkuId(sku.getSkuId());
        asnItem.setSkuDesc(sku.getDescCn());
        asnItem.setSkuDescEn(sku.getDescEn());

        asnItem.setLotno(goodsItem.getLotno());

        asnItem.setOrderQty(BigDecimal.ZERO);
        asnItem.setOrderQtyEa(BigDecimal.ZERO);

        asnItem.setRcvQty(BigDecimal.ZERO);
        asnItem.setRcvQtyEa(BigDecimal.ZERO);

        asnItem.setUnit(sku.getBaseUnit());
        asnItem.setInvAttr(goodsItem.getInvAttr());

        asnItem.setRcvTime(new Date());
        asnItem.setRcvLocId(null);
        asnItem.setPlanLocId(null);

        asnItem.setReserveLocFlag(null);
        asnItem.setInvAttr(goodsItem.getInvAttr());
        asnItem.setInvType(null);

        asnItem.setWhsId(asnHeader.getToWhs());

        asnItem.setQcStatus(QcStatusEnum.已创建质检单.getCode());
        asnItem.setQaStatus(QaStatusEnum.WAIT.getCode());

        asnItem.setInspNo(goodsItem.getInspNo());
        asnItem.setSoNo(goodsItem.getSoNo());
        asnItem.setSoLineNo(goodsItem.getSoItem());

        asnItem.setLotAttr1(lotInfo.getLotAttr1());
        asnItem.setLotAttr2(lotInfo.getLotAttr2());
        asnItem.setLotAttr3(lotInfo.getLotAttr3());
        asnItem.setLotAttr4(lotInfo.getLotAttr4());
        asnItem.setLotAttr5(lotInfo.getLotAttr5());
        asnItem.setLotAttr6(lotInfo.getLotAttr6());
        asnItem.setLotAttr7(lotInfo.getLotAttr7());
        asnItem.setLotAttr8(lotInfo.getLotAttr8());
        asnItem.setLotAttr9(lotInfo.getLotAttr9());
        asnItem.setLotAttr10(lotInfo.getLotAttr10());
        asnItem.setLotAttr11(lotInfo.getLotAttr11());
        asnItem.setLotAttr12(lotInfo.getLotAttr12());
        asnItem.setDataSource("ERP");

        asnItem.setStatus(AsnDtlStatusEnum.CREATE.getCode());
        asnItem.setCreateUser(userName);
        asnItem.setModifyUser(userName);
        asnItem.setCreateTime(new Date());
        asnItem.setModifyTime(new Date());
        return asnItem;
    }

    /**
     * @param listGoods
     * @param userName
     * @param asnItem
     * @return
     */
    private List<AsnDtlGoods> setAsnDtlGoodsList(List<Goods> listGoods, String userName, AsnDtl asnItem) {
        List<AsnDtlGoods> listAsnDtlGoods = new ArrayList<>();
        for (Goods goods : listGoods) {
            AsnDtlGoods item = new AsnDtlGoods();
            item.setAsnDtlId(asnItem.getAsnDtlId());
            item.setGoodsId(goods.getGoodsId());
            item.setGoodsSn(goods.getGoodsSn());
            item.setQaStatus(goods.getQaStatus());
            item.setQty(goods.getQty());
            item.setComments("");
            item.setStatus(AsnDtlGoodsStatusEnum.已接收.getCode());
            item.setCreateUser(userName);
            item.setModifyUser(userName);
            item.setCreateTime(new Date());
            item.setModifyTime(new Date());
            listAsnDtlGoods.add(item);
        }
        return listAsnDtlGoods;
    }

    /*赋值 TrsnHeader*/
    private TrsnHeader setTrsnHeader(AsnHeader asnHeader) {
        TrsnHeader item = new TrsnHeader();
        item.setNoteNo(basicSimpleCodeRuleApi.GenerateCode(trsnRuleCode));
        item.setNoteType(TrsnNoteTypeEnum.IN_STORAGE.getCode()); //凭证类型
        item.setOwner(asnHeader.getOwner());
        item.setFactory(asnHeader.getFactory());
        item.setWhsId(asnHeader.getToWhs());
        item.setVendorId(asnHeader.getVendorId());
        item.setFmDoc(asnHeader.getAsnNo()); //来源单据
        item.setStatus(TrsnHeaderStatusEnum.CMP.getCode());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        item.setModifyUser(asnHeader.getModifyUser());
        item.setCreateUser(asnHeader.getModifyUser());
        return item;
    }

    /*赋值 TrsnDtl*/
    private TrsnDtl setTrsnDtl(AsnHeader asnHeader, AsnDtl asnDtl, List<AsnDtlGoods> asnDtlGoodsList, int rowIndex) {
        TrsnDtl item = new TrsnDtl();

        item.setNoteLineNo(String.valueOf(rowIndex));
        item.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.IN.getCode());
        item.setFmDoc(asnDtl.getAsnNo());
        item.setFmDocLine(asnDtl.getAsnLineNo());
        item.setSkuId(asnDtl.getSkuId());
        item.setQty(asnDtlGoodsList.stream().map(AsnDtlGoods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add));
        item.setUnit(asnDtl.getUnit());

        item.setQaStatus(asnDtl.getQaStatus());

        item.setInvAttr(asnDtl.getInvAttr());
        item.setLotAttr1(asnDtl.getLotAttr1());
        item.setLotAttr2(asnDtl.getLotAttr2());
        item.setLotAttr3(asnDtl.getLotAttr3());
        item.setLotAttr4(asnDtl.getLotAttr4());
        item.setLotAttr5(asnDtl.getLotAttr5());
        item.setLotAttr6(asnDtl.getLotAttr6());
        item.setLotAttr7(asnDtl.getLotAttr7());
        item.setLotAttr8(asnDtl.getLotAttr8());
        item.setLotAttr9(asnDtl.getLotAttr9());
        item.setLotAttr10(asnDtl.getLotAttr10());
        item.setLotAttr11(asnDtl.getLotAttr11());
        item.setLotAttr12(asnDtl.getLotAttr12());
        item.setStatus(TrsnDtlStatusEnum.CMP.getCode());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        item.setModifyUser(asnHeader.getModifyUser());
        item.setCreateUser(asnHeader.getModifyUser());
        return item;
    }


    /*赋值 List<TrsnDtlGoods>*/
    private List<TrsnDtlGoods> setTrsnDtlGoods(TrsnDtl trsnDtl, List<AsnDtlGoods> asnDtlGoodsList) {
        List<TrsnDtlGoods> list = new ArrayList<>();
        for (AsnDtlGoods dtlGoods : asnDtlGoodsList) {
            TrsnDtlGoods item = new TrsnDtlGoods();
            item.setTrsnDtlId(trsnDtl.getTrsnDtlId());
            item.setGoodsId(dtlGoods.getGoodsId());
            item.setGoodsSn(dtlGoods.getGoodsSn());
            item.setQaStatus(dtlGoods.getQaStatus());
            item.setQty(dtlGoods.getQty());
            item.setComments("");
            item.setStatus(TrsnDtlGoodsStatusEnum.RECEIVED.getCode());
            item.setQaStatus(dtlGoods.getQaStatus());
            item.setCreateUser(trsnDtl.getModifyUser());
            item.setModifyUser(trsnDtl.getModifyUser());
            item.setCreateTime(new Date());
            item.setModifyTime(new Date());
            list.add(item);
        }
        return list;
    }
    //TODO ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    //TODO ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    //TODO ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    //TODO ————————————————————————————————————————————————————————————————————————————————————————————————————————————




    public List<SnInforDto> selectSnInfosBySn(String sn, SnScanTypeEnum type) {
        List<SnInforDto> list = null;
        if (type == SnScanTypeEnum.SELECT_SN) { //单sn查询
            list = goodsManagerMapper.selectSnsBySnOrPalletId(sn, null);
        } else {
            //1. 根据sn获取到包装表的ID
            Integer pkgId = goodsMapper.selectPkgIdBySn(sn);
            if (pkgId != null) {
                //2. 根据包装ID获取包装URL
                String url = goodsPkgMapper.selectUrlById(pkgId);
                if (StringUtils.isNotNull(url)) {
                    //3. 路径用'_'分开, 取第一位  最上层的ID
                    Integer palletId = Integer.valueOf(url.substring(0, url.indexOf("_")));
                    //4. 通过路径获取 所有的 sn
                    list = goodsManagerMapper.selectSnsBySnOrPalletId(null, palletId);
                }
            } else {
                Shift.fatal("该SN没有整板外包装");
            }
        }
        return list;
    }
}
